/**
 * 
 */
package org.sgt.datamodel.edit.provider;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.sgt.datamodel.DatamodelPackage;
import org.sgt.datamodel.ReferenceValue;

/**
 * @author abutti
 *
 */
public class ReferenceValueItemPropertyDescriptor extends ItemPropertyDescriptor {

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EReference[] parentReferences,
			boolean isSettable, String category, String[] filterFlags) {
		super(adapterFactory, resourceLocator, displayName, description,
				parentReferences, isSettable, category, filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EReference[] parentReferences,
			boolean isSettable, String category) {
		super(adapterFactory, resourceLocator, displayName, description,
				parentReferences, isSettable, category);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EReference[] parentReferences,
			boolean isSettable) {
		super(adapterFactory, resourceLocator, displayName, description,
				parentReferences, isSettable);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EReference[] parentReferences) {
		super(adapterFactory, resourceLocator, displayName, description,
				parentReferences);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable,
			boolean multiLine, boolean sortChoices, Object staticImage,
			String category, String[] filterFlags) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable, multiLine, sortChoices, staticImage, category, filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable,
			Object staticImage, String category, String[] filterFlags) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable, staticImage, category, filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable,
			Object staticImage, String category) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable, staticImage, category);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable,
			Object staticImage) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable, staticImage);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable,
			String category, String[] filterFlags) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable, category, filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable,
			String category) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable, category);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature, boolean isSettable) {
		super(adapterFactory, resourceLocator, displayName, description, feature,
				isSettable);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			ResourceLocator resourceLocator, String displayName,
			String description, EStructuralFeature feature) {
		super(adapterFactory, resourceLocator, displayName, description, feature);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description,
			EReference[] parentReferences, boolean isSettable, String category,
			String[] filterFlags) {
		super(adapterFactory, displayName, description, parentReferences, isSettable,
				category, filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description,
			EReference[] parentReferences, boolean isSettable, String category) {
		super(adapterFactory, displayName, description, parentReferences, isSettable,
				category);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description,
			EReference[] parentReferences, boolean isSettable) {
		super(adapterFactory, displayName, description, parentReferences, isSettable);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description,
			EReference[] parentReferences) {
		super(adapterFactory, displayName, description, parentReferences);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature,
			boolean isSettable, Object staticImage, String category,
			String[] filterFlags) {
		super(adapterFactory, displayName, description, feature, isSettable,
				staticImage, category, filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature,
			boolean isSettable, Object staticImage, String category) {
		super(adapterFactory, displayName, description, feature, isSettable,
				staticImage, category);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature,
			boolean isSettable, Object staticImage) {
		super(adapterFactory, displayName, description, feature, isSettable,
				staticImage);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature,
			boolean isSettable, String category, String[] filterFlags) {
		super(adapterFactory, displayName, description, feature, isSettable, category,
				filterFlags);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature,
			boolean isSettable, String category) {
		super(adapterFactory, displayName, description, feature, isSettable, category);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature,
			boolean isSettable) {
		super(adapterFactory, displayName, description, feature, isSettable);
	}

	public ReferenceValueItemPropertyDescriptor(AdapterFactory adapterFactory,
			String displayName, String description, EStructuralFeature feature) {
		super(adapterFactory, displayName, description, feature);
	}

	  protected Collection<?> getComboBoxObjects(Object object)
	  {
	    if (object instanceof EObject)
	    {
	      if (parentReferences != null)
	      {
	        Collection<Object> result = new UniqueEList<Object>();
	        for (int i = 0; i < parentReferences.length; ++i)
	        {
	          result.addAll(getReachableObjectsOfType((EObject)object, parentReferences[i].getEType()));
	        }
	        return result;
	      }
	      else if (feature != null)
	      {
	    	EClassifier restricted = ((ReferenceValue)object).getType();
	    	EClassifier type = feature.getEType();
	        if (feature instanceof EReference)
	        {
		      if (restricted instanceof EClass && ((EClass)feature.getEType()).isSuperTypeOf((EClass)restricted)){
		        type = restricted;
		      }
	          Collection<EObject> result = getReachableObjectsOfType((EObject)object, type );
	          Collection<EObject> refs = getReachableObjectsOfType((EObject)object, DatamodelPackage.eINSTANCE.getReferenceValue() );
	          Collection<EObject> remove = new ArrayList<EObject>(); 
	          for (EObject eObj : refs){
	        	  if (type == EcorePackage.eINSTANCE.getEClass()) break;
	              ReferenceValue ref = (ReferenceValue) eObj;
	        	  if (type != EcorePackage.eINSTANCE.getEClass() && ref.getType() instanceof EClass){
	        		  EClass refType = (EClass) ref.getType();
	        		  if (type != refType && !((EClass)type).isSuperTypeOf(refType)){
	        			  remove.add(eObj);
	        		  }
	        	  }
	          }
	          if (!remove.isEmpty()){
	        	  refs.removeAll(remove);
	          }
	          result.addAll(refs);
	          if (!feature.isMany() && !result.contains(null))
	          {
	            result.add(null);
	          }
	          return result;
	        }
	        else if (feature.getEType() instanceof EEnum)
	        {
	          EEnum eEnum = (EEnum)feature.getEType();
	          List<Enumerator> enumerators = new ArrayList<Enumerator>();
	          for (EEnumLiteral eEnumLiteral :  eEnum.getELiterals())
	          {
	            enumerators.add(eEnumLiteral.getInstance());
	          }
	          return enumerators;
	        }
	        else 
	        {
	          EDataType eDataType = (EDataType)feature.getEType();
	          List<String> enumeration = ExtendedMetaData.INSTANCE.getEnumerationFacet(eDataType);
	          if (!enumeration.isEmpty())
	          {
	            List<Object> enumerators = new ArrayList<Object>();
	            for (String enumerator : enumeration)
	            {
	              enumerators.add(EcoreUtil.createFromString(eDataType, enumerator));
	            }
	            return enumerators;
	          }
	        }
	      }
	    }

	    return null;
	  }
}
